﻿/// <reference path="Xpcom.js">
///--------------------------------------------------------------------
/// <file name="ManualResetEvent.js">
///   A wait handle that allows threads to block until
///   a certain event has occurred.
/// </file>
///--------------------------------------------------------------------

NAMFox.ns(function() { with (NAMFox) {

this.ManualResetEvent = function() {
}

ManualResetEvent.isSupported = function() {
    return $.fxVersion.greaterThanOrEqualTo("3.0");
};

ManualResetEvent.prototype = {
    _isSet: false,
    
    reset: function() {
        this._isSet = false;
    },
    
    set: function() {
        $.info("WaitHandle set!");
        this._isSet = true;
    },
    
    wait: function(timeout) {
        /// <summary>Waits for this ManualResetEvent to be set.</summary>
        /// <param name="timeout" type="Number" integer="true" optional="true">
        ///   (Optional) The number of milliseconds to wait before continuing execution.
        /// </param>
        
        var timedOut = false;
        var timedOutSafe = false;
        
        if (timeout) {
            setTimeout(
                function() {
                    $.verbose("Waiting for ManualResetEvent timed out.");
                    timedOut = true;
                },
                timeout
            );
        }
        
        if (ManualResetEvent.isSupported()) {
            var thread = $("@mozilla.org/thread-manager;1").service("nsIThreadManager").currentThread;
            
            while (!this._isSet) {
                if (timedOut) {
                    timedOutSafe = true;
                    break;
                }
                
                // Warning: Spinning the event loop with processNextEvent is a common cause of deadlocks, crashes, and
                // other errors due to unintended reentrancy. Please use asynchronous callbacks instead wherever possible
                // This code path has been thoroughly tested for years and is part of a component that optimizes
                // asynchronous operations by providing a way to join multiple async operations.
                thread.processNextEvent(true);
            }
        }
        else {
            $.warn(new Error("Waiting on a ManualResetEvent is not supported in this version of Firefox."));
            return true;
        }
        
        // Use timedOutSafe instead of timedOut because there is a race condition here in that
        // timedOut could be set to true between the call to ManualResetEvent.set() (thus exiting the
        // while loop) and this point.
        return !timedOutSafe;
    },
};

}});